#include "Player.h"

Player::Player()
{
}

//CREATE SCENE
void Player::createScene()
{
	//CREATE CUBE
	//Ogre::Plane plane(Vector3::UNIT_Y, -10);
	//Ogre::MeshManager::getSingleton().createPlane("plane", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, plane,
	//	500,500,1,1,true,1,5,5,Vector3::UNIT_Z);
	//Ogre::Entity* ent = mSceneMgr->createEntity("LightPlaneEntity", "plane");
	//mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(ent);
	//ent->setMaterialName("Examples/BeachStones");
	
	//CREATE LIGHT
	Ogre::Light* light = mSceneMgr->createLight("Light1");
	light->setType(Ogre::Light::LT_POINT);
	light->setPosition(50, 100, 50);
	light->setPowerScale(10);

	//CREATE SINBAD
	Ogre::SceneNode* node = mSceneMgr->createSceneNode("Node1");
	mSceneMgr->getRootSceneNode()->addChild(node);
	_SinbadEnt = mSceneMgr->createEntity("Sinbad", "Sinbad.mesh");
	_SinbadNode = node->createChildSceneNode("SinbadNode");
	_SinbadNode->setScale(3.0f,3.0f,3.0f);
	_SinbadNode->setPosition(Ogre::Vector3(0.0f,4.0f,50.0f));
	mSceneMgr->getSceneNode("SinbadNode")->createChildSceneNode()->attachObject(_SinbadEnt);

	//INIT POSITION CHARACTER
	setupAnimations();

	//INIT PRIME_SENSE
	initPrimeSensor();
}

//CREATE CAMERA
void Player::createCamera() {

	mCamera = mSceneMgr->createCamera("MyCamera1");
	mCamera->setPosition(0,25,-30);
	mCamera->lookAt(0,23,0);
	mCamera->setNearClipDistance(1);
}

//CREATE UPDATE FUNCTION
void Player::createFrameListener()
{
	FrameListener = new CustomFrameListener(mSceneMgr, _SinbadNode, _SinbadEnt, mWindow, mCamera, m_Context, m_pSessionManager, m_UserGenerator, m_candidateID);
	mRoot->addFrameListener(FrameListener);
}

//SETUP BONES POSITION
void Player::setupBone(const String& name,const Ogre::Radian& angle, const Vector3 axis)
{
	Quaternion q;
	q.FromAngleAxis(angle,axis);	 
	setupBone(name, q);
}

void Player::setupBone(const String& name,const Degree& yaw,const Degree& pitch,const Degree& roll)
{
	Ogre::Bone* bone = _SinbadEnt->getSkeleton()->getBone(name);
	bone->setManuallyControlled(true);
	bone->setInheritOrientation(false);

	bone->resetOrientation();

	bone->yaw(yaw);
	bone->pitch(pitch);
	bone->roll(roll);

	//Matrix3 mat = bone->getLocalAxes();
	bone->setInitialState();

}

void Player::setupBone(const String& name,const Ogre::Quaternion& q)
{
	Ogre::Bone* bone = _SinbadEnt->getSkeleton()->getBone(name);
	bone->setManuallyControlled(true);
	bone->setInheritOrientation(false);

	bone->resetOrientation();
	bone->setOrientation(q);

	bone->setInitialState();
}

//SETUP BODY POSITION AND INIT BONES
void Player::setupAnimations()
{
	// this is very important due to the nature of the exported animations
	_SinbadEnt->getSkeleton()->setBlendMode(ANIMBLEND_CUMULATIVE);	

	Ogre::Quaternion q = Quaternion::IDENTITY;
	Quaternion q2,q3;
	Vector3 xAxis,yAxis,zAxis;
	q.FromAngleAxis(Ogre::Degree(90),Vector3(0,0,-1));
	q.ToAxes(xAxis,yAxis,zAxis);
	q2.FromAngleAxis(Ogre::Degree(90),xAxis);
	setupBone("Humerus.L",q*q2);
	q.FromAngleAxis(Ogre::Degree(90),Vector3(0,0,1));
	q.ToAxes(xAxis,yAxis,zAxis);
	q2.FromAngleAxis(Ogre::Degree(90),xAxis);
	setupBone("Humerus.R",q*q2);

	q.FromAngleAxis(Ogre::Degree(90),Vector3(0,0,-1));	 
	q2.FromAngleAxis(Ogre::Degree(45),Vector3(0,-1,0));
	setupBone("Ulna.L",q*q2);

	q.FromAngleAxis(Ogre::Degree(90),Vector3(0,0,1));	 	
	setupBone("Ulna.R",q*q2.Inverse());

	q.FromAngleAxis(Ogre::Degree(180),Vector3(0,1,0));
	setupBone("Chest",q);
	setupBone("Stomach",q);

	q.FromAngleAxis(Ogre::Degree(180),Vector3(1,0,0));	 	
	q2.FromAngleAxis(Ogre::Degree(180),Vector3(0,1,0));
	setupBone("Thigh.L",q*q2);
	setupBone("Thigh.R",q*q2);
	setupBone("Calf.L",q*q2);
	setupBone("Calf.R",q*q2);

	setupBone("Root",Degree(0),Degree(0),Degree(0));
}


//INIT PRIME_SENSE
XnStatus Player::initPrimeSensor()
{
	m_hUserCallbacks = NULL;
	m_hPoseCallbacks = NULL;
	m_hCalibrationCallbacks = NULL;

	// Init OpenNI from XML
	XnStatus rc = XN_STATUS_OK;	
	rc = m_Context.InitFromXmlFile("C:/Users/Alfy/Desktop/hciproject/HCIProject/Debug/openNi.xml");//"$(ProjectDir)/$(Configuration)/openNi.xml"); //set correct path
	assert(rc == XN_STATUS_OK);

	// Make sure we have all OpenNI nodes we will be needing for this sample
	xn::NodeInfoList nodes;

	// Init NITE Controls (UI stuff)
	m_pSessionManager = new XnVSessionManager;
	rc = m_pSessionManager->Initialize(&m_Context, "Click", "RaiseHand");
	assert(rc == XN_STATUS_OK);
	m_pSessionManager->SetQuickRefocusTimeout(0);

	VALIDATE_GENERATOR(XN_NODE_TYPE_USER, "User", m_UserGenerator);

	// Init OpenNI nodes
	m_UserGenerator.RegisterUserCallbacks(Player::NewUser, Player::LostUser, this, m_hUserCallbacks);
	m_UserGenerator.GetPoseDetectionCap().RegisterToPoseCallbacks(Player::PoseDetected, Player::PoseLost, this, m_hPoseCallbacks);

	// Skeleton stuff
	xn::SkeletonCapability skel = m_UserGenerator.GetSkeletonCap();
	skel.SetSkeletonProfile(XN_SKEL_PROFILE_ALL);
	skel.RegisterCalibrationCallbacks(Player::CalibrationStart, Player::CalibrationEnd, this, m_hCalibrationCallbacks);

	// Make sure OpenNI nodes start generating
	rc = m_Context.StartGeneratingAll();
	assert(rc == XN_STATUS_OK);

	m_candidateID = 0;
	m_pStartPoseDetector = new StartPoseDetector(3.0);
	m_pEndPoseDetector = new EndPoseDetector(m_UserGenerator, 2.0);
	m_pEndPoseDetector->SetUserId(m_candidateID);

	return XN_STATUS_OK;
}
